#ifndef ACAPELLA_WORKER_THREAD_WORKER_HPP
#define ACAPELLA_WORKER_THREAD_WORKER_HPP

#include <acapella/thread/thread.h>
#include <acapella/queue/queue.h>
#include "worker_base.hpp"

namespace acapella
{
namespace worker
{

template<
    typename FunctorType, 
    typename BindType = acapella::delegate::dynamic_bind, 
    typename ClassType = acapella::delegate::ClassStub
    >
class ThreadWorker : public worker<FunctorType, BindType, ClassType>
{
public:
    typedef worker<FunctorType, BindType, ClassType> parent;
    typedef typename parent::functor_type functor_type; 

	ThreadWorker(functor_type _functor)
        :parent(_functor), pQueue_(new acapella::queue::SimpleQueue<TaskPtr>)
	{
        _Init();
	}

    ~ThreadWorker()
    {
        Join();
    }

    int Exit()
    {
        return _Exit();
    }

	int Join()
	{
		return _Join();
	}
private:

    virtual int _Exit()
    {
        typedef acapella::delegate::delegate<int(_uint32_)> exit_delegate_type;
        typedef acapella::shared_ptr<exit_delegate_type> exit_delegate_ptr;
        
        exit_delegate_ptr pExit(new exit_delegate_type(
                                    &acapella::thread::Thread::Exit, 0));
        
        TaskPtr pTask(new AsynTask<exit_delegate_type>(pExit));
        
        parent::Schedule(pTask);
        
        return 0;
    }

	virtual int _Join()
	{
		return thread_.Join(NULL);
	}

    virtual int _Init()
    {
        thread_.SetUserFunction(
            acapella::thread::Thread::functor_type(
                this, 
                &ThreadWorker<FunctorType, BindType, ClassType>::_ThreadFunc)
            );
        thread_.Create(this, 0);

        return 0;
    }

    void _Schedule(typename parent::task_pointer_type pTask)
    {
        pQueue_->Send(pTask);
    }

    int _ThreadFunc(void * /*param*/)
    {
        TaskPtr pTask;
        while (pQueue_->Recv(pTask) == 0)
        {
            pTask->run();
        }
        return 0;
    }
    
    TaskQueuePtr pQueue_;
    acapella::thread::Thread thread_;
};

}
}



#endif
